package com.mxpio.erp.hr.service.impl;

import cn.hutool.core.date.DateUtil;
import com.mxpio.erp.common.enums.BizExceptionEnums;
import com.mxpio.erp.common.enums.CommonEnums;
import com.mxpio.erp.common.hr.entity.AttendanceMonth;
import com.mxpio.erp.common.hr.entity.Employee;
import com.mxpio.erp.common.hr.entity.EmployeeSalary;
import com.mxpio.erp.common.hr.service.AttendanceCalendarService;
import com.mxpio.erp.common.hr.service.EmployeeSalaryService;
import com.mxpio.erp.common.util.AssertUtil;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.policy.impl.CrudType;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class EmployeeSalaryServiceImpl extends BaseServiceImpl<EmployeeSalary> implements EmployeeSalaryService {

    @Resource
    private AttendanceCalendarService attendanceCalendarService;
    @Override
    @Transactional
    public void calculateSalary(String yearMonth) {
        try {
            DateUtil.parse(yearMonth, "yyyy-MM");
        } catch (Exception e) {
            throw new MBootException("输入的日期格式不正确(yyyy-MM，例：2025-01)-》"+yearMonth);
        }
        List<AttendanceMonth> summarys = JpaUtil.linq(AttendanceMonth.class).equal("yearMonth", yearMonth).list();
        if (summarys.isEmpty()){
            throw new MBootException("未获取到该月份员工月度考勤汇总记录，请先测算员工月度考勤汇总！");
        }

        List<EmployeeSalary> addOrUpdateList = new ArrayList<>();
        for (AttendanceMonth summary : summarys){
            StringBuffer detail = new StringBuffer();
            Employee employee = JpaUtil.getOne(Employee.class, summary.getUsername());
            if (employee == null){
                log.error("不存在的员工信息！【"+summary.getUsername()+"】");
                throw new MBootException("不存在的员工信息！【"+summary.getUsername()+"】");
            }
            detail.append("员工【").append(employee.getEmployeeCode()).append(":").append(summary.getNickname()).append("】").append(yearMonth).append("月度薪资计算如下：\n");
            EmployeeSalary salary = JpaUtil.linq(EmployeeSalary.class).equal("yearMonth", yearMonth).equal("employeeCode", summary.getUsername()).findOne();
            if (salary == null){
                salary = new EmployeeSalary();
                salary.setEmployeeCode(summary.getUsername());
                salary.setName(summary.getNickname());
                salary.setYearMonth(summary.getYearMonth());
                salary.setCrudType(CrudType.SAVE);
                salary.setIsLabor(employee.getIsLabor());
            }else{
                //如果薪资测算表不为空,并且已结账, 就不允许在测算
                if (CommonEnums.YesNo.YES.getCode().equals(salary.getHasFinish())) {
                    throw new MBootException(String.format(BizExceptionEnums.EMPLOYEE_SALARY_IS_FINISH_NOT_COMPUTE.getMsg(), yearMonth));
                }
                salary.setCrudType(CrudType.UPDATE);
                salary.setIsLabor(employee.getIsLabor());
            }
            if (StringUtils.equals(CommonEnums.YesNo.YES.getCode(), employee.getIsLabor())){//
                detail.append("计算模式：劳务工\n");
                BigDecimal attendanceDays = summary.getAttendanceDays();//出勤天数
                detail.append("出勤天数："+attendanceDays+"天。\n");
                BigDecimal workHours = attendanceDays.multiply(new BigDecimal("8"));
                detail.append("工作时长："+workHours+"小时。\n");
                BigDecimal overTimeHours = summary.getOnePointFiveHours().add(summary.getDoubleHours()).add(summary.getThriceHours());
                detail.append("加班时长："+overTimeHours+"小时。\n");
                BigDecimal sum = workHours.add(overTimeHours);
                detail.append("工作时长+加班时长："+sum+"小时。\n");
                BigDecimal laborHourSalary = new BigDecimal("17").multiply(sum);
                salary.setLaborHourSalary(laborHourSalary);
                detail.append("工时工资："+laborHourSalary+"元。\n");
                BigDecimal laborManageCost = new BigDecimal("4").multiply(sum);
                salary.setLaborManageCost(laborManageCost);
                detail.append("工时管理费："+laborManageCost+"元。\n");
                salary.setSalary(laborHourSalary.add(laborManageCost).setScale(2, BigDecimal.ROUND_HALF_UP));
                detail.append("合计："+salary.getSalary()+"元。\n");
            }else{
                detail.append("计算模式：正式工\n");
                //工龄：
                salary.setEntryTime(employee.getEntryTime());
                detail.append("工龄：");
                if (employee.getEntryTime()!=null){
                    long l = DateUtil.betweenYear(employee.getEntryTime(), new Date(), false);
                    salary.setWorkYearSubsidy(new BigDecimal(l*100+""));
                    detail.append(l+"年，补贴标准100元/年，补贴金额："+l*100+"元。\n");
                }else{
                    detail.append("不存在入职时间！\n");
                    salary.setWorkYearSubsidy(BigDecimal.ZERO);
                }
                //绩效
                detail.append("绩效：");
                if (employee.getPerformancebasedPay()==null){
                    log.error("员工【"+summary.getUsername()+"】绩效为空！");
                    throw new MBootException("员工【"+summary.getUsername()+"】绩效为空！");
                }
                detail.append("岗位绩效"+employee.getPerformancebasedPay()+"；");
                salary.setPerformancebasedPay(employee.getPerformancebasedPay());
                detail.append("得分"+summary.getPerformanceScore()+"分；");
                salary.setPerformancebasedSalary(employee.getPerformancebasedPay().multiply(summary.getPerformanceScore()));
                detail.append("绩效工资(岗位绩效*得分)："+salary.getPerformancebasedSalary()+"元。\n");

                //基本工资 岗位工资/月工作天数*出勤天数
                detail.append("基本工资：");
                if (employee.getFixedSalary()==null){
                    log.error("员工【"+summary.getUsername()+"】岗位工资为空！");
                    throw new MBootException("员工【"+summary.getUsername()+"】岗位工资为空！");
                }
                detail.append("岗位工资"+employee.getFixedSalary()+"元；");
                Integer workDays = attendanceCalendarService.getWorkDays(yearMonth);
                detail.append("月工作天数"+workDays+"天；");
                detail.append("出勤天数"+summary.getAttendanceDays()+"天；");
                salary.setBaseSalary(employee.getFixedSalary().multiply(summary.getAttendanceDays()).divide(new BigDecimal(workDays+""),4,BigDecimal.ROUND_HALF_UP));
                detail.append("计算结果(岗位工资/月工作天数*出勤天数)："+salary.getBaseSalary()+"元。\n");

                //全勤
                detail.append("全勤：");
                if (StringUtils.equals(summary.getFullFlag(), CommonEnums.YesNo.YES.getCode())){
                    salary.setFullAttendanceSubsidy(new BigDecimal("100"));
                    detail.append("是，");
                }else{
                    salary.setFullAttendanceSubsidy(BigDecimal.ZERO);
                    detail.append("否，");
                }
                detail.append(salary.getFullAttendanceSubsidy()+"元。\n");

                //岗位补贴
                detail.append("岗位补贴：");
                if (employee.getPostSubsidyAmount()!=null){
                    salary.setPostSubsidy(employee.getPostSubsidyAmount());
                }else{
                    salary.setPostSubsidy(BigDecimal.ZERO);
                }
                detail.append(salary.getPostSubsidy()+"元。\n");
                //餐费补贴
                detail.append("餐费补助：");
                if (summary.getMealSubsidy()!=null){
                    salary.setMealSubsidy(summary.getMealSubsidy());
                }else{
                    salary.setMealSubsidy(BigDecimal.ZERO);
                }
                detail.append(salary.getMealSubsidy()+"元。\n");
                //住宿补贴
                detail.append("住宿津贴：");
                if (employee.getStaySubsidyAmount()!=null){
                    salary.setStaySubsidy(employee.getStaySubsidyAmount());
                }   else{
                    salary.setStaySubsidy(BigDecimal.ZERO);
                }
                detail.append(salary.getStaySubsidy()+"元。\n");
                //其他 todo
                //detail.append("奖惩：");
                salary.setRewardOrPunishment(BigDecimal.ZERO);
                //加班工时费用
                detail.append("加班工时费：");
                detail.append("岗位工资"+employee.getFixedSalary());
                detail.append("/月工作天数"+workDays+"天/8=");
                BigDecimal hourFee = employee.getFixedSalary().divide(new BigDecimal(workDays + ""), 4, BigDecimal.ROUND_HALF_UP).divide(new BigDecimal("8"), 4, BigDecimal.ROUND_HALF_UP);
                detail.append(hourFee.toPlainString()+"元/小时；");
                //平时加班
                detail.append("平时加班：");
                if (summary.getOnePointFiveHours()!=null){
                    salary.setOnePointFiveHoursPay(summary.getOnePointFiveHours().multiply(hourFee).multiply(new BigDecimal("1.5")));
                    detail.append(summary.getOnePointFiveHours().toPlainString()+"小时，");
                }else{
                    salary.setOnePointFiveHoursPay(BigDecimal.ZERO);
                    detail.append("0小时，");
                }
                detail.append("小计"+salary.getOnePointFiveHoursPay()+"元。\n");
                //周末加班
                detail.append("周末加班：");
                if (summary.getDoubleHours()!=null){
                    salary.setDoubleHoursPay(summary.getDoubleHours().multiply(hourFee).multiply(new BigDecimal("2")));
                    detail.append(summary.getDoubleHours().toPlainString()+"小时，");
                }else{
                    salary.setDoubleHoursPay(BigDecimal.ZERO);
                    detail.append("0小时，");
                }
                detail.append("小计"+salary.getDoubleHoursPay()+"元。\n");
                //节假日加班
                detail.append("节假日加班：");
                if (summary.getThriceHours()!=null){
                    salary.setThriceHoursPay(summary.getThriceHours().multiply(hourFee).multiply(new BigDecimal("3")));
                    detail.append(summary.getThriceHours().toPlainString()+"小时，");
                }else{
                    salary.setThriceHoursPay(BigDecimal.ZERO);
                    detail.append("0小时，");
                }
                detail.append("小计"+salary.getThriceHoursPay()+"元。\n");

                //合计
                detail.append("合计：");
                salary.setSalary(salary.getWorkYearSubsidy()
                        .add(salary.getPerformancebasedSalary())
                        .add(salary.getBaseSalary())
                        .add(salary.getFullAttendanceSubsidy())
                        .add(salary.getPostSubsidy())
                        .add(salary.getMealSubsidy())
                        .add(salary.getStaySubsidy())
                        .add(salary.getRewardOrPunishment())
                        .add(salary.getOnePointFiveHoursPay())
                        .add(salary.getDoubleHoursPay())
                        .add(salary.getThriceHoursPay()).setScale(2, BigDecimal.ROUND_HALF_UP));
                detail.append(salary.getSalary()+"元。\n");
            }
            salary.setDetail(detail.toString());
            addOrUpdateList.add(salary);
        }
        JpaUtil.save(addOrUpdateList);
    }

    @Override
    @Transactional
    public void finishSalary(String yearMonth) {
        //1. 检查如果该月份员工薪资没核算给提示
        List<EmployeeSalary> salary = JpaUtil.linq(EmployeeSalary.class).equal("yearMonth", yearMonth).list();

        AssertUtil.notEmpty(salary, BizExceptionEnums.EMPLOYEE_SALARY_NOT_COMPUTE, yearMonth);

        EmployeeSalary root = salary.stream().findFirst().orElseGet(null);

        AssertUtil.notNull(root, BizExceptionEnums.EMPLOYEE_SALARY_IS_FINISH, yearMonth);

        //2. 更新状态
        salary.forEach(employeeSalary -> employeeSalary.setHasFinish(CommonEnums.YesNo.YES.getCode()));

        this.update(salary);
    }
}
